package com.young.common.core.event;

import com.young.common.core.concurrent.YoungThreadPoolExecutor;
import com.young.common.core.concurrent.rejected.YoungDiscardPolicy;
import com.young.common.util.CollectionUtil;
import com.young.common.util.JsonUtil;
import com.young.interfaces.common.event.model.EventMessage;
import com.young.interfaces.common.event.model.IEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;


/**
 * 事件调度器
 *
 * @author wangjy
 * @date 2021/10/16 00:22:58
 */
@Component
public class EventControlCenter implements ApplicationContextAware {

    private static final Logger logger = LoggerFactory.getLogger(EventControlCenter.class);
    /**
     * 事件与订阅者的关联关系
     * key是xx事件, value是订阅该事件的订阅者
     */
    private static Map<IEvent, Set<IEventSubscriber>> EVENT_SUBSCRIBER_RELATION = new HashMap<>();

//    private static ExecutorService threadPool = YoungThreadPoolExecutor.builder("AsyncEventThreadPool").workQueue(new LinkedBlockingDeque<>(200)).rejectedHandler(new YoungDiscardPolicy()).build();


    /**
     * 事件调度器初始化
     *
     * @param applicationContext
     * @throws BeansException
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        logger.info("[事件调度中心-初始化] 初始化开始...");
        // 获取所有的订阅bean
        Map<String, IEventSubscriber> map = applicationContext.getBeansOfType(IEventSubscriber.class);
        if (CollectionUtil.isNotEmpty(map)) {
            for (Map.Entry<String, IEventSubscriber> entry : map.entrySet()) {
                IEventSubscriber subscriber = entry.getValue();
                // 获取订阅者订阅的事件数组并订阅
                this.register(subscriber);
            }

            // 获取所有的事件
            Set<IEvent> eventSet = EVENT_SUBSCRIBER_RELATION.keySet();
            if (CollectionUtil.isEmpty(eventSet)) {
                Set<String> eventNameSet = new HashSet<>();
                for (IEvent event : eventSet) {
                    if (eventNameSet.contains(event.eventName())) {
                        logger.warn("[事件调度中心-初始化] 存在重复name的事件,name={},事件对象={},建议修改事件name,保持name唯一", event.eventName(), event);
                    }
                    eventNameSet.add(event.eventName());
                }
            }
        } else {
            logger.info("[事件调度中心-初始化] 当前上下文中事件订阅器为空.");
        }
        logger.info("[事件调度中心-初始化] 初始化完成!");
    }

    /**
     * 订阅指定事件
     *
     * @param subscriber 订阅者
     */
    private void register(IEventSubscriber subscriber) {
        if (subscriber == null) {
            logger.error("[事件调度中心-注册订阅] 订阅失败:入参订阅者为null");
            return;
        }
        if (CollectionUtil.isEmpty(subscriber.events())) {
            logger.error("[事件调度中心-注册订阅] 订阅失败:订阅的事件为空,订阅者={},事件={}", subscriber, JsonUtil.toJson(subscriber.events()));
            return;
        }
        for (IEvent event : subscriber.events()) {
            // 查询事件对应的订阅者列表
            Set<IEventSubscriber> subscriberSet = EVENT_SUBSCRIBER_RELATION.get(event);
            if (subscriberSet == null) {
                subscriberSet = new HashSet<>();
                EVENT_SUBSCRIBER_RELATION.put(event, subscriberSet);
            }
            subscriberSet.add(subscriber);
            logger.info("[事件调度中心-注册订阅] 事件订阅成功,订阅者={},事件名={}", subscriber, event.eventName());
        }
    }

    /**
     * 发布事件
     *
     * @param message 消息对象
     */
    public static void publish(EventMessage message) {
        if (message == null) {
            return;
        }
        if (message.getEvent() == null) {
            logger.error("[事件调度中心-发布事件] 待发布事件消息中的事件为空,事件消息={}", JsonUtil.toJson(message));
            return;
        }
        // 查询事件关联的订阅列表
        Set<IEventSubscriber> subscriberSet = EVENT_SUBSCRIBER_RELATION.get(message.getEvent());
        if (CollectionUtil.isEmpty(subscriberSet)) {
            logger.warn("[事件调度中心-发布事件] 事件[{}]对应的订阅列表为空!", message.getEvent().eventName());
            return;
        }

        for (IEventSubscriber subscriber : subscriberSet) {
            logger.info("[事件调度中心-发布事件] 订阅执行,事件={},订阅者={},消息对象={}"
                    , message.getEvent().eventName(), subscriber, JsonUtil.toJson(message));
            subscriber.process(message);
        }
    }
}
